class Watcher {
  constructor (vm, expr, cb) {
    this.vm = vm
    this.expr = expr
    this.cb = cb
    // 保存旧值
    this.oldVal = this.getOldVal()
  }
  getOldVal () {
    Dep.target = this
    const oldVal = compileUtil.getVal(this.expr, this.vm) // 这里会触发属性的getter，从而添加订阅者
    Dep.target =null
    return oldVal
  }
  // 3、待属性变动dep.notice()通知时，能调用自身的update()方法，并触发Compile中绑定的回调
  update () {
    const newVal = compileUtil.getVal(this.expr, this.vm)
    if (newVal !== this.oldVal) {
      this.cb(newVal)
    }
  }
}

class Dep {
  constructor () {
    this.subs = []
  }
  // 收集观察者
  addSub (watcher) {
    this.subs.push(watcher)
  }
  // 通知观察者更新
  notify () {
    console.log('通知了观察者', this.subs);
    this.subs.forEach(w => w.update())
  }
}
// 4...
// 属性关联 dep (属性订阅器)
class Observer {
  constructor (data) {
    this.observe(data)
  }
  // 遍历数据 --> 劫持
  observe (data) {
    if (data && typeof data === 'object') {
      Object.keys(data).forEach(key => {
        this.defineReactive(data, key, data[key])
      })
    }
  }
  // 劫持数据
  defineReactive (obj, key, value) {
    this.observe(value)
    const dep = new Dep()
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: false,
      get () {
        // 订阅数据变化时,往dep中添加观察者
        Dep.target && dep.addSub(Dep.target)
        return value
      },
      set: (newVal) => {
        this.observe(newVal)
        if (newVal !== value) {
          value = newVal
        }
        // 告诉dep通知变化
        dep.notify()
      }
    })
  }
}